using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;
using System.Data;
using System.IO;
using System.Globalization;
using System.Web;

namespace MosziNET.Web.Gallery.Providers
{

    internal class HybridFolder : Folder
    {
        public string Path;
    }

    /// <summary>
    /// Provides the means to store the image files on the file system
    /// </summary>
    public class HybridGalleryStorageProvider : GalleryStorageProvider
    {
        #region / Private fields /

        private const string folderPath = "gallery/{0}";
        private const string imagePath = "gallery/{0}/{1}";

        private string connectionString;
        private SqlCommand folderListSelectCommand;
        private SqlParameter folderListSelectParam;

        private SqlCommand folderSelectCommand;
        private SqlParameter folderSelectParam;

        #endregion / Private fields /

        #region / Constructors /

        /// <summary>
        /// Creates a new instance of the storage provider
        /// </summary>
        public HybridGalleryStorageProvider()
        {
            folderListSelectCommand = new SqlCommand("SELECT * FROM gallery_Folder WHERE parent_id_fk = @ParentID");
            folderListSelectParam = folderListSelectCommand.Parameters.Add("@ParentID", SqlDbType.Int);

            folderSelectCommand = new SqlCommand("SELECT * FROM gallery_Folder WHERE folder_id_pk = @FolderID");
            folderSelectParam = folderSelectCommand.Parameters.Add("@FolderID", SqlDbType.Int);
        }

        #endregion / Constructors /

        #region / Public properties /

        /// <summary>
        /// Gets/sets the connection string for the database
        /// </summary>
        public override string ConnectionString
        {
            get
            {
                return this.connectionString;
            }
            set
            {
                this.connectionString = value;
            }
        }

        #endregion / Public properties /

        #region / GalleryStorageProvider implementation /

        /// <summary>
        /// Returns the folder list of the parent folder
        /// </summary>
        /// <param name="parentFolderId"></param>
        /// <returns></returns>
        protected override Folder[] GetFolderListInternal(string parentFolderId)
        {
            List<Folder> folderList = new List<Folder>();

            using (SqlConnection con = new SqlConnection(this.ConnectionString))
            {
                // set up the connection
                folderListSelectCommand.Connection = con;
                folderListSelectParam.Value = Convert.ToInt32(parentFolderId);

                // open the connection
                con.Open();

                // get the data
                SqlDataReader reader = folderListSelectCommand.ExecuteReader(CommandBehavior.CloseConnection);
                while (reader.Read())
                {
                    folderList.Add(GetFolder(reader));
                }
            }

            return folderList.ToArray();
        }

        /// <summary>
        /// Verifies if the cached file exists and if yes, returns it
        /// </summary>
        /// <param name="thumbnailId"></param>
        /// <returns></returns>
        public override byte[] GetCachedThumbnail(string thumbnailId)
        {
            string fileName = HttpContext.Current.Server.MapPath(
                String.Format("{0}/galleryID{1}", GalleryManager.CacheFolder, thumbnailId));

            if (System.IO.File.Exists(fileName))
            {
                byte[] response = null;
                using (Stream s = File.OpenRead(fileName))
                {
                    response = new byte[s.Length];
                    s.Read(response, 0, (int)s.Length);

                    return response;
                }
            }

            return null;
        }

        /// <summary>
        /// Writes the content to the cache file
        /// </summary>
        /// <param name="thumbnailId"></param>
        /// <param name="content"></param>
        public override void CacheThumbnail(string thumbnailId, byte[] content)
        {
            string fileName = HttpContext.Current.Server.MapPath(
                String.Format("{0}/galleryID{1}", GalleryManager.CacheFolder, thumbnailId));
            using (FileStream s = File.Create(fileName))
            {
                s.Write(content, 0, content.Length);
                s.Flush();
            }
        }

        /// <summary>
        /// Gets the specified image from the persistence medium
        /// </summary>
        /// <param name="image"></param>
        /// <returns></returns>
        public override Stream GetImage(FolderImage image)
        {
            HybridFolder folder = GetFolder(image.ParentFolder) as HybridFolder;
            if (folder != null)
            {
                string imageName = FixPhysicalPath(String.Format(CultureInfo.InvariantCulture,
                    imagePath, folder.Path, image.ImageName));

                if (File.Exists(imageName))
                {
                    return File.Open(imageName, FileMode.Open, FileAccess.Read, FileShare.Read);
                }
            }

            return null;
        }

        /// <summary>
        /// Returns the folder information based on the folder id
        /// </summary>
        /// <param name="folderId"></param>
        /// <returns></returns>
        protected override Folder GetFolderInternal(string folderId)
        {
            using (SqlConnection con = new SqlConnection(this.ConnectionString))
            {
                folderSelectCommand.Connection = con;
                folderSelectParam.Value = Convert.ToInt32(folderId);
                con.Open();

                SqlDataReader reader = folderSelectCommand.ExecuteReader(CommandBehavior.CloseConnection);
                if (reader.Read())
                {
                    return GetFolder(reader);
                }
            }

            return null;
        }

        /// <summary>
        /// Returns the image list
        /// </summary>
        /// <param name="parentFolderId"></param>
        /// <returns></returns>
        protected override FolderImage[] GetImageListInternal(string parentFolderId)
        {
            List<FolderImage> images = new List<FolderImage>();

            try
            {
                HybridFolder folder = GetFolder(parentFolderId) as HybridFolder;
                if (folder != null)
                {
                    string path = FixPhysicalPath(String.Format(CultureInfo.InvariantCulture,
                        folderPath, folder.Path));
                    string[] files = Directory.GetFiles(path);

                    for (int i = 0; i < files.Length; i++)
                    {
                        FolderImage newImage = new FolderImage();
                        newImage.ParentFolder = parentFolderId;
                        newImage.ImageName = Path.GetFileName(files[i]);

                        images.Add(newImage);
                    }
                }
            }
            catch (DirectoryNotFoundException)
            { }

            return images.ToArray();
        }

        #endregion / GalleryStorageProvider implementation /

        #region / Helper methods /

        /// <summary>
        /// Returns a folder instance from the reader
        /// </summary>
        /// <param name="reader"></param>
        /// <returns></returns>
        private HybridFolder GetFolder(SqlDataReader reader)
        {
            HybridFolder newFolder = new HybridFolder();

            newFolder.Id = reader.GetInt32(0).ToString(); // folder id
            newFolder.Title = reader.GetString(1); // folder name

            newFolder.Thumbnail = new FolderImage();
            if (!reader.IsDBNull(5)) // thumbnail folder
                newFolder.Thumbnail.ParentFolder = reader.GetInt32(5).ToString();
            newFolder.Thumbnail.ImageName = reader.GetString(6); // thumbnail image

            newFolder.Path = reader.GetString(3); // folder path

            return newFolder;
        }

        /// <summary>
        /// Combines the application root path with the given one
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        private string FixPhysicalPath(string path)
        {
            if (HttpContext.Current == null)
            {
                return String.Empty;
            }

            if (String.IsNullOrEmpty(path))
                return HttpContext.Current.Request.PhysicalApplicationPath;

            if (path.StartsWith("~/"))
                path = path.Substring(2);

            return String.Format(
                    CultureInfo.InvariantCulture, "{0}/{1}",
                    HttpContext.Current.Request.PhysicalApplicationPath,
                    path);
        }

        #endregion / Helper methods /
    }
}
